home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / progjour / 1991 / 03 / cam.pas < prev    next >
Pascal/Delphi Source File  |  1991-04-16  |  11KB  |  393 lines

  1. unit CAM;
  2.  
  3. {$A-}
  4.  
  5. { This Turbo Pascal 6.0 unit is an object-oriented interface to
  6.   BallardSynergy's CAMpatible SCSI drivers, Version 1.302.
  7.   Please note that the CAM specification is still in flux
  8.   so these bindings may need to change to accommodate changes
  9.   in the interface. }
  10.  
  11. { Turbo Pascal bindings Copyright (C) 1991 by Brett Glass, All Rights Reserved.
  12.   Original C bindings, sample code, and assembly language Copyright (C) 1990
  13.    by BallardSynergy, All Rights Reserved. Used with permission. }
  14.  
  15. interface
  16.  
  17. function CAMPresent : Boolean; { Return TRUE if a CAM driver is installed }
  18.  
  19. { This enumerated type gives the CAM function codes for the BallardSynergy
  20.   implementation of CAM, version 1.302. The numbering is different from
  21.   that found in the CAM UNIX bindings and in Microsoft's LADDR spec. }
  22.  
  23. type CAMFunctionCode = (
  24.   FUNC_UNUSED_00,
  25.   FUNC_ABORT_SCSI_COMMAND,
  26.   FUNC_EXECUTE_SCSI_IO,
  27.   FUNC_GET_DEVICE_TYPE,
  28.   FUNC_UNUSED_04,
  29.   FUNC_PATH_INQUIRY,
  30.   FUNC_RELEASE_SIM_QUEUE,
  31.   FUNC_RESET_SCSI_BUS,
  32.   FUNC_RESET_SCSI_DEVICE,
  33.   FUNC_SET_ASYNC_CALLBACK,
  34.   FUNC_SET_DEVICE_TYPE,
  35.   FUNC_SET_HBA_PARAMETERS,
  36.   {Create dummy names to reserve unused function numbers}
  37.   FUNC_UNUSED_0C, FUNC_UNUSED_0D, FUNC_UNUSED_0E, FUNC_UNUSED_0F,
  38.   FUNC_UNUSED_10, FUNC_UNUSED_11, FUNC_UNUSED_12, FUNC_UNUSED_13,
  39.   FUNC_UNUSED_14, FUNC_UNUSED_15, FUNC_UNUSED_16, FUNC_UNUSED_17,
  40.   FUNC_UNUSED_18, FUNC_UNUSED_19, FUNC_UNUSED_1A, FUNC_UNUSED_1B,
  41.   FUNC_UNUSED_1C, FUNC_UNUSED_1D, FUNC_UNUSED_1E, FUNC_UNUSED_1F,
  42.   FUNC_CHANGE_OS2_NAME,
  43.   FUNC_ROM_DEBUGS);
  44.  
  45. type
  46.   SCSIid = 0..7;
  47.  
  48. { This abstract superclass is the "father" of all classes of CAM
  49.   Control Blocks (CCBs). }
  50.  
  51. type CCB = object
  52.   ccbLen : Word;     {Length of CAM Control Block (CCB)}
  53.   funcCode : CAMFunctionCode;   {XPT Function Code}
  54.   camStatus : Byte;  {Returned CAM subsystem status}
  55.   scsiStatus : Byte; {Returned SCSI status}
  56.   pathId : Byte;     {Adapter to do request}
  57.   camFlags : Longint; {Flags containing transaction parameters}
  58.  
  59.   {Note: CCB.Setup is called by the constructors of the child
  60.    classes of CCB, but is *not* a constructor itself. If
  61.    it were, a VMT pointer would be allocated between the
  62.    fields of this parent class and the fields of child classes,
  63.    causing everything to be misaligned. It's OK for the
  64.    child classes to have constructors. }
  65.  
  66.   procedure Setup(func : CAMFunctionCode; len : Word);
  67.   procedure Submit;
  68.   end;
  69.  
  70. type CCBAddr = ^CCB;
  71.  
  72. { Constants for the CAM flags in the BallardSynergy implementation.
  73.   These are different from the UNIX definitions that appear in the
  74.   CAM spec. }
  75.  
  76. const
  77.   CAM_DATA_DIRECTION               = $C0000000;  { BITS 30 & 31 }
  78.   CAM_DISABLE_AUTOSENSE            = $20000000;  { BIT 29 }
  79.   CAM_DATAPTR_IS_SG_LIST_PTR       = $10000000;  { BIT 28 }
  80.   CAM_DO_NOT_CALLBACK              = $08000000;  { BIT 27 }
  81.   CAM_LINKED_COMMAND               = $04000000;  { BIT 26 }
  82.   CAM_QUEUE_ACTION_SPECIFIED       = $02000000;  { BIT 25 }
  83.   CAM_CDB_FIELD_IS_CDB_PTR         = $01000000;  { BIT 24 }
  84.   CAM_DO_NOT_ALLOW_DISCONNECT      = $00800000;  { BIT 23 }
  85.   CAM_INIT_SYNC_TRANSFERS          = $00400000;  { BIT 22 }
  86.   CAM_DISABLE_SYNC_TRAN            = $00200000;  { BIT 21 }
  87.   CAM_CDBPTR_IS_PHYS_ADDR          = $00004000;  { BIT 14 }
  88.   CAM_DATAPTR_IS_PHYS_ADDR         = $00002000;  { BIT 13 }
  89.   CAM_SENSEPTR_IS_PHYS_ADDR        = $00001000;  { BIT 12 }
  90.   CAM_MSGPTR_IS_PHYS_ADDR          = $00000800;  { BIT 11 }
  91.   CAM_LINKPTR_IS_PHYS_ADDR         = $00000400;  { BIT 10 }
  92.   CAM_CALLBACKPTR_IS_PHYS_ADDR     = $00000200;  { BIT  9 }
  93.   CAM_DATA_BUFFER_VALID            = $00000080;  { BIT  7 }
  94.   CAM_STATUS_VALID                 = $00000040;  { BIT  6 }
  95.   CAM_MESSAGE_BUFFER_VALID         = $00000020;  { BIT  5 }
  96.   CAM_RESERVED_BITS                = $001F811F;  { BITS 1-4,8,14-20 }
  97.  
  98.   CAM_DATA_DIRECTION_CLEAR         = $3FFFFFFF;  { BITS 30 & 31  }
  99.  
  100.   CAM_DIR_DATA_IN                  = $40000000;
  101.   CAM_DIR_DATA_OUT                 = $80000000;
  102.   CAM_DIR_NO_DATA                  = $C0000000;
  103.  
  104.   DATA_IN  = 1;
  105.   DATA_OUT = 0;
  106.  
  107. { Status codes returned by CAM }
  108.  
  109. const
  110.   STAT_REQUEST_IN_PROGRESS            = $00;
  111.   STAT_REQUEST_DONE_NO_ERROR          = $01;
  112.   STAT_ABORTED_BY_HOST                = $02;
  113.   STAT_UNABLE_TO_ABORT                = $03;
  114.   STAT_COMPLETE_WITH_ERROR            = $04;
  115.   STAT_CAM_BUSY                       = $05;
  116.   STAT_INVALID_REQUEST                = $06;
  117.   STAT_INVALID_PATH_ID                = $07;
  118.   STAT_SCSI_DEVICE_NOT_INSTALLED      = $08;
  119.   STAT_WAIT_FOR_TIMEOUT               = $09;
  120.   STAT_SELECTION_TIMEOUT              = $0A;
  121.   STAT_COMMAND_TIMEOUT                = $0B;
  122.   STAT_SCSI_BUS_BUSY                  = $0C;
  123.   STAT_MESSAGE_REJECT_RECIEVED        = $0D;
  124.   STAT_SCSI_BUS_RESET                 = $0E;
  125.   STAT_UNCORRECTED_PARITY_ERROR       = $0F;
  126.   STAT_REQUEST_SENSE_FAILED           = $10;
  127.   STAT_NO_HBA_DETECTED_ERROR          = $11;
  128.   STAT_DATA_OVERRUN_OR_UNDERRUN       = $12;
  129.   STAT_UNEXPECTED_BUS_FREE            = $13;
  130.   STAT_PHASE_SEQUENCE_FAILURE         = $14;
  131.   STAT_CCB_LENGTH_INADEQUATE          = $15;
  132.   STAT_CANNOT_PROVIDE_CAPABILITY      = $16;
  133.   STAT_INVALID_LUN                    = $20;
  134.   STAT_INVALID_TARGET_ID              = $21;
  135.   STAT_FUNCTION_NOT_IMPLEMENTED       = $22;
  136.   STAT_NEXUS_NOT_ESTABLISHED          = $23;
  137.   STAT_INVALID_INTIATOR_ID            = $24;
  138.   STAT_INVALID_DATA_BUFFER            = $25;
  139.  
  140. { Values for flags that appear at top of status code }
  141.  
  142. const
  143.   FLAG_SIM_QUEUE_FROZEN = $40;
  144.   FLAG_AUTOSENSE_DATA_VALID = $80;
  145.  
  146. const
  147.   INQUIRY_DATA_LEN = 36; {Length of data returned from device
  148.                           inquiry. Defined by SCSI-1 and unlikely
  149.                           to change in the future...}
  150.  
  151. type
  152.   InquiryData = array [0..Pred(INQUIRY_DATA_LEN)] of Byte;
  153.   InquiryDataAddr = ^InquiryData;
  154.  
  155. type AbortXPTRequestCCB = object(CCB)
  156.   ccbPtr : CCBAddr;
  157.   constructor Init;
  158.   end;
  159.  
  160. type GetDeviceTypeCCB = object(CCB)
  161.   targetID : SCSIid;
  162.   lun : Byte;
  163.   deviceType : Byte;
  164.   inquiryDataPtr : InquiryDataAddr;
  165.   constructor Init;
  166.   end;
  167.  
  168. type SetDeviceTypeCCB = object(CCB)
  169.   targetID : SCSIid;
  170.   lun : Byte;
  171.   deviceType : Byte;
  172.   constructor Init;
  173.   end;
  174.  
  175. type ResetSCSIBusCCB = object(CCB)
  176.   constructor Init;
  177.   end;
  178.  
  179. type ResetSCSIDeviceCCB = object(CCB)
  180.   targetID : SCSIid;
  181.   hostStatus : Byte;
  182.   targetStatus : Byte;
  183.   constructor Init;
  184.   end;
  185.  
  186. type ReleaseSIMQueueCCB = object(CCB)
  187.   targetID : SCSIid;
  188.   lun : Byte;
  189.   constructor Init;
  190.   end;
  191.  
  192. const
  193.   SIM_ID_LEN = 16;
  194.   HBA_ID_LEN = 16;
  195.   VU_HBA_LEN = 16;
  196.  
  197. type
  198.   SIMid = array [0..Pred(SIM_ID_LEN)] of Char;
  199.   HBAid = array [0..Pred(HBA_ID_LEN)] of Char;
  200.   VUhba = array [0..Pred(VU_HBA_LEN)] of Char;
  201.  
  202. const
  203.  FEAT_SOFT_RESET_SUPPORTED            = $01;
  204.  FEAT_COMMAND_QUEUING_SUPPORTED       = $02;
  205.  FEAT_LINKED_COMMANDS_SUPPORTED       = $08;
  206.  FEAT_SYNCHRONOUS_TRANSFER_SUPPORTED  = $01;
  207.  FEAT_SCSI_BUS_SUPPORTED_16_BIT       = $02;
  208.  FEAT_SCSI_BUS_SUPPORTED_32_BIT       = $04;
  209.  FEAT_RELATIVE_ADDRESSING_SUPPORTED   = $08;
  210.  
  211. type PathInquiryCCB = object(CCB)
  212.   featureList : Longint;
  213.   highestPathID : Byte;
  214.   initiatorID : SCSIid;
  215.   simVendorName : SIMid;
  216.   hbaVendorName : HBAid;
  217.   vendorUnique : VUhba;
  218.   privateDataSize : Longint;
  219.   OSD : Pointer;
  220.   constructor Init;
  221.   end;
  222.  
  223. type SetHBAParametersCCB = object(CCB)
  224.   featureList : Longint;
  225.   constructor Init;
  226.   end;
  227.  
  228. type Proc = Procedure;
  229. type ProcPtr = ^Proc;
  230.  
  231. type AENFlag = (
  232.   AEN_UNSOLICITED_SCSI_BUS_RESET,
  233.   AEN_UNSOLICITED_RESELECTION,
  234.   AEN_RECOVERED_FROM_PARITY_ERROR,
  235.   AEN_SCSI_ASYNCRONOUS_EVENT_NOTIFY);
  236.  
  237. type AENFlagSet = set of AENFlag;
  238.  
  239. type AsyncCallbackCCB = object(CCB)
  240.   targetID : SCSIid;
  241.   lun : Byte;
  242.   aenFlags : AENFlagSet;
  243.   callbackPtr : ProcPtr;
  244.   constructor Init;
  245.   end;
  246.  
  247. const
  248.   CDB_LEN = 16;
  249.  
  250. type CDBType = array [0..Pred(CDB_LEN)] of Byte;
  251.  
  252. const
  253.   SCSI_REQUEST_FILL_SIZE = 113;
  254.  
  255. type SCSIRequestCCB = object(CCB)
  256.   targetID : SCSIid;
  257.   lun : Byte;
  258.   queueAction : Byte;
  259.   vendorFlags : Word;
  260.   cdbLength : Word;
  261.   senseLength : Word;
  262.   messageLength : Word;
  263.   sgListLength : Word;
  264.   dataLength : Longint;
  265.   timeOut : Longint;
  266.   dataPtr : Pointer;
  267.   sensePtr : Pointer;
  268.   messagePtr : Pointer;
  269.   linkPtr : CCBAddr;
  270.   peripheralPtr : Pointer;
  271.   callBackPtr : ProcPtr;
  272.   unused : array [1..2] of Pointer;
  273.   cdb : CDBType;
  274.   filler : array [1..SCSI_REQUEST_FILL_SIZE] of Byte;
  275.   constructor Init;
  276.   end;
  277.  
  278.  
  279. implementation
  280.  
  281. uses DOS; {For type Registers}
  282.  
  283. procedure CCB.Setup(func : CAMFunctionCode; len : Word);
  284. begin
  285. FillChar(self, len, 0); {Zero out the CCB}
  286. funcCode := func;       {Set the function code and length}
  287. ccbLen := len;
  288. end;
  289.  
  290. procedure CCB.Submit;
  291. var
  292.   regs : Registers;
  293. begin
  294. regs.bx := Ofs(self);
  295. regs.es := Seg(self);
  296. regs.ax := $C3D4; {Sentinel}
  297. Intr($4B,regs);
  298. end;
  299.  
  300. constructor AbortXPTRequestCCB.Init;
  301. begin
  302. CCB.Setup(FUNC_ABORT_SCSI_COMMAND, Sizeof(self));
  303. end;
  304.  
  305. constructor GetDeviceTypeCCB.Init;
  306. begin
  307. CCB.Setup(FUNC_GET_DEVICE_TYPE, Sizeof(self));
  308. end;
  309.  
  310. constructor SetDeviceTypeCCB.Init;
  311. begin
  312. CCB.Setup(FUNC_SET_DEVICE_TYPE, Sizeof(self));
  313. end;
  314.  
  315. constructor ResetSCSIBusCCB.Init;
  316. begin
  317. CCB.Setup(FUNC_RESET_SCSI_BUS, Sizeof(self));
  318. end;
  319.  
  320. constructor ResetSCSIDeviceCCB.Init;
  321. begin
  322. CCB.Setup(FUNC_RESET_SCSI_DEVICE, Sizeof(self));
  323. end;
  324.  
  325. constructor ReleaseSIMQueueCCB.Init;
  326. begin
  327. CCB.Setup(FUNC_RELEASE_SIM_QUEUE, Sizeof(self));
  328. end;
  329.  
  330. constructor PathInquiryCCB.Init;
  331. begin
  332. CCB.Setup(FUNC_PATH_INQUIRY, Sizeof(self));
  333. end;
  334.  
  335. constructor SetHBAParametersCCB.Init;
  336. begin
  337. CCB.Setup(FUNC_SET_HBA_PARAMETERS, Sizeof(self));
  338. end;
  339.  
  340. constructor AsyncCallbackCCB.Init;
  341. begin
  342. CCB.Setup(FUNC_SET_ASYNC_CALLBACK, Sizeof(self));
  343. end;
  344.  
  345. constructor SCSIRequestCCB.Init;
  346. begin
  347. CCB.Setup(FUNC_EXECUTE_SCSI_IO, Sizeof(self));
  348. end;
  349.  
  350. function CAMPresent : Boolean;
  351. { This function tests for the presence of a CAM driver. It's
  352.   taken directly from the code in BallardSynergy's CAM Development
  353.   Kit. Turbo's inline assembler makes it unnecessary to do the
  354.   assembly as a separate step. }
  355. label
  356.   no_cam;
  357. begin
  358. CAMPresent := FALSE;
  359. asm
  360.   xor ax,ax
  361.   mov es,ax
  362.   mov bx,$012C
  363.   les bx,dword ptr es:[bx]
  364.   add bx,8
  365.   cmp byte ptr es:[bx],'S'
  366.   jne no_cam
  367.   cmp byte ptr es:[bx+1],'C'
  368.   jne no_cam
  369.   cmp byte ptr es:[bx+2],'S'
  370.   jne no_cam
  371.   cmp byte ptr es:[bx+3],'I'
  372.   jne no_cam
  373.   cmp byte ptr es:[bx+4],'_'
  374.   jne no_cam
  375.   cmp byte ptr es:[bx+5],'C'
  376.   jne no_cam
  377.   cmp byte ptr es:[bx+6],'A'
  378.   jne no_cam
  379.   cmp byte ptr es:[bx+7],'M'
  380.   jne no_cam
  381.   mov byte ptr @Result,TRUE
  382. no_cam:
  383.   end;
  384. end;
  385.  
  386. begin {Module init code}
  387. if not CAMPresent then
  388.   begin
  389.   Writeln('CAM driver not present in system');
  390.   Halt
  391.   end;
  392. end.
  393.